////
//
/// \file   ./src/parse_tree_node.cpp
//
//  Copyright 2007, 2008 Chandler Carruth
//
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not
//  use this file except in compliance with the License.  You may obtain a copy
//  of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
//  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
//  License for the specific language governing permissions and limitations
//  under the License.
//
////

#include  <stdlib.h>
#include  <string.h>
#include  <inttypes.h>
#include  <cassert>

#include  <inc/parser/parse_tree_node.hpp>

namespace inc {
namespace parser {

/// \brief  Generic ParseTreeNode destructor
/// \author Chandler Carruth
/// \date   2008.05.02
///
/// This destroys the tree components of a particular node. All other cleanup
/// is left to the subclass destructors.

ParseTreeNode::~ParseTreeNode()
{
  unlink();

  // We manage our own iteration in cleaning up our children to decrease the
  // chance of an infinite loop or segmentation fault due to faulty unlink
  // process.
  ParseTreeNode *n = front;
  while( n != NULL )
  {
    ParseTreeNode *tmp = n;
    n = n->next;
    delete n;
  }
}

/// \brief  Link this node into a tree
/// \author Chandler Carruth
/// \date   2008.05.02
///
/// This links the node into a tree data structure. Providing parent and next
/// nodes to hook into allows controlling both under which node, and where
/// within the sequence of siblings to link. When 'n' is NULL or omitted, this
/// node gets inserted on the *back* of the siblings of the provided parent.
///
/// Prerequisites: if 'p' and 'n' are not null, then p == n->parent.
///
/// \param[in]  p The parent node to link with
/// \param[in]  n The sibling to link in front of

bool
ParseTreeNode::link( ParseTreeNode* p, ParseTreeNode* n )
{
  assert( p == NULL || n == NULL || p == n->parent );

  parent = p;
  next = n;

  if( next == NULL )
  {
    if( parent != NULL )
    {
      prev = parent->back;
      parent->back = this;
    }
  }
  else
  {
    prev = next->prev;
    next->prev = this;
  }

  if( prev != NULL )
    prev->next = this;
  else if( parent != NULL )
    parent->front = this;

  return true;
}

/// \brief  Unlink the node from a tree
/// \author Chandler Carruth
/// \date   2008.05.02
///
/// This method unlinks a node from its tree. It returns false when there was
/// no tree linked in or an error occurred. It returns true on successful
/// removal from the tree.

bool
ParseTreeNode::unlink()
{
  if( next != NULL )
    next->prev = prev;
  else if( parent != NULL )
    parent->back = prev;

  if( prev != NULL )
    prev->next = next;
  else if( parent != NULL )
    parent->front = next;

  parent = NULL;
  next = NULL;
  prev = NULL;

  return true;
}

} //  end parser namespace
} //  end inc namespace
